package com.beiben.statistics.service.impl;

import com.beiben.common.GlobalConstant;
import com.beiben.statistics.ServiceUtils;
import com.beiben.statistics.mapper.CompositeMapper;
import com.beiben.statistics.service.ICompositeService;
import com.beiben.statistics.service.IWorkService;
import com.beiben.statistics.vo.*;
import com.beiben.utils.DateUtil;
import com.beiben.work.process.domain.FileProcessUser;
import com.ruoyi.common.utils.Arith;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class CompositeServiceImpl implements ICompositeService {


    @Autowired
    IWorkService workService;

    @Autowired
    private CompositeMapper compositeMapper;


    /**
     * 查询统计所的总工作工时
     * @param recordSearchParamVo
     * @return
     */
    @Override
    public List<CompositeDateVo> selectWorkDeptSuo(RecordSearchParamVo recordSearchParamVo) throws ParseException {
        List<CompositeDateVo>  comResultList = new ArrayList<>();
        ServiceUtils.setSearchTime(recordSearchParamVo);
        recordSearchParamVo.setWorkType(GlobalConstant.EVERY_DAY_WORK);
        List<WorkItemVo> everyDay = compositeMapper.selectWorkDeptSuo(recordSearchParamVo);
        recordSearchParamVo.setWorkType(GlobalConstant.PROJECT_WORK);
        List<WorkItemVo> project = compositeMapper.selectWorkDeptSuo(recordSearchParamVo);
        comResultList = ServiceUtils.nvChangeCv(comResultList,recordSearchParamVo,everyDay,project);
        return comResultList;
    }
    /**
     * 查询统计科室的总工作工时
     * @param recordSearchParamVo
     * @return
     */
    @Override
    public List<CompositeDateVo> selectWorkDeptShi(RecordSearchParamVo recordSearchParamVo) throws ParseException {
        List<CompositeDateVo> comResultList = new ArrayList<>();
        ServiceUtils.setSearchTime(recordSearchParamVo);
        recordSearchParamVo.setWorkType(GlobalConstant.EVERY_DAY_WORK);
        List<WorkItemVo> everyDay = compositeMapper.selectWorkDeptShi(recordSearchParamVo);
        recordSearchParamVo.setWorkType(GlobalConstant.PROJECT_WORK);
        List<WorkItemVo> project = compositeMapper.selectWorkDeptShi(recordSearchParamVo);
        comResultList = ServiceUtils.nvChangeCv(comResultList,recordSearchParamVo,everyDay,project);
        return comResultList;
    }
    /**
     * 查询统计所工作饱和度
     * @param recordSearchParamVo
     * @return
     */
    @Override
    public List<CompositeDateVo> selectAbilityDeptAverageSuo(RecordSearchParamVo recordSearchParamVo) throws ParseException {
        List<CompositeDateVo> list = selectWorkDeptSuo(recordSearchParamVo);
        List<NameValueVo> plist = compositeMapper.selectWorkHoursPeopleSuo(recordSearchParamVo);
        list = setValue(list, plist, recordSearchParamVo);
        list.sort(Comparator.comparing(CompositeDateVo::getTotalValue).reversed());
        return list;
    }
    /**
     * 查询统计科室工作饱和度
     * @param recordSearchParamVo
     * @return
     */
    @Override
    public List<CompositeDateVo> selectAbilityDeptAverageShi(RecordSearchParamVo recordSearchParamVo) throws ParseException {
        List<CompositeDateVo> list = selectWorkDeptShi(recordSearchParamVo);
        List<NameValueVo> plist = compositeMapper.selectWorkHoursPeopleShi(recordSearchParamVo);
        list = setValue(list, plist, recordSearchParamVo);
        list.sort(Comparator.comparing(CompositeDateVo::getTotalValue).reversed());
        return list;
    }

    /**
     * 查询统计人员总工时
     * @param recordSearchParamVo
     * @return
     */
    @Override
    public List<CompositeDateVo> selectWorkTotalPeople(RecordSearchParamVo recordSearchParamVo) throws ParseException {
        List<CompositeDateVo> comResultList = new ArrayList<>();
        ServiceUtils.setSearchTime(recordSearchParamVo);
        recordSearchParamVo.setWorkType(GlobalConstant.EVERY_DAY_WORK);
        List<WorkItemVo> everyDay = compositeMapper.selectWorkTotalPeople(recordSearchParamVo);
        recordSearchParamVo.setWorkType(GlobalConstant.PROJECT_WORK);
        List<WorkItemVo> project = compositeMapper.selectWorkTotalPeople(recordSearchParamVo);
        comResultList = ServiceUtils.nvChangeCv(comResultList,recordSearchParamVo,everyDay,project);
        return comResultList;
    }
    /**
     * 查询统计人员工作饱和度
     * @param recordSearchParamVo
     * @return
     */
    @Override
    public List<CompositeDateVo> selectWorkAvgPeople(RecordSearchParamVo recordSearchParamVo) throws ParseException {
        List<CompositeDateVo> list = selectWorkTotalPeople(recordSearchParamVo);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        long day = DateUtil.getDatePoorDay(sdf.parse(recordSearchParamVo.getEndTime()), sdf.parse(recordSearchParamVo.getBeginTime())) + 1;
        for (CompositeDateVo nv : list) {
            boolean isValue = false;
            if(null!=nv.getWorkValue()&&0!=nv.getWorkValue()&&null != nv.getHours()){
                Double workValue = Arith.mul(Arith.div(Arith.div(nv.getWorkValue(), day, 4), nv.getHours(), 4), 100);
                nv.setWorkValue(workValue);
                isValue = true;
            }else{
                nv.setWorkValue(0.0);
            }
            if(null!=nv.getProjectValue()&&0!=nv.getProjectValue()&&null != nv.getHours()){
                Double projectValue = Arith.mul(Arith.div(Arith.div(nv.getProjectValue(), day, 4), nv.getHours(), 4), 100);
                nv.setProjectValue(projectValue);
                isValue = true;
            }else{
                nv.setProjectValue(0.0);
            }
            if(null!=nv.getTotalValue()&&0!=nv.getTotalValue()&&null != nv.getHours()){
                Double totalValue = Arith.mul(Arith.div(Arith.div(nv.getTotalValue(), day, 4), nv.getHours(), 4), 100);
                nv.setTotalValue(totalValue);
            }else{
                nv.setTotalValue(0.0);
            }

        }
        list.sort(Comparator.comparing(CompositeDateVo::getTotalValue).reversed());
        return list;
    }

    /**
     * 查询人员所有工作总量曲线（近30天）
     * @param recordSearchParamVo
     * @return
     */
    @Override
    public List<CompositeDateVo> selectWorkLinePeople(RecordSearchParamVo recordSearchParamVo) throws ParseException {
        //当前用户名、用户Id
        if(null==recordSearchParamVo.getUserId()){
            recordSearchParamVo.setUserId(recordSearchParamVo.getDeptId());
        }
        Integer hours = compositeMapper.selectUserWorkHours(recordSearchParamVo);
        ServiceUtils.setLineSearchTime(recordSearchParamVo);
        recordSearchParamVo.setWorkType(GlobalConstant.EVERY_DAY_WORK);
        List<FileProcessUser> everyProcessUser = compositeMapper.selectFileProcessUserList(recordSearchParamVo);
        recordSearchParamVo.setWorkType(GlobalConstant.PROJECT_WORK);
        List<FileProcessUser> projectProcessUser = compositeMapper.selectFileProcessUserList(recordSearchParamVo);
        List<LineDataVo> workList = countLineData(recordSearchParamVo,everyProcessUser);
        List<LineDataVo> projectList = countLineData(recordSearchParamVo,projectProcessUser);
        List<CompositeDateVo> list = ServiceUtils.lvChangeCv(workList,projectList);

        for (CompositeDateVo compositeDateVo : list ) {
            compositeDateVo.setHours(Double.valueOf(hours));
        }
        // TODO: 2020/10/27 根据日期排序
        if (list.size() > 0) {
            list.sort(Comparator.comparing(CompositeDateVo::getTime));
        } else {
            list = null;
        }
        return list;
    }
    /*
     * 人员近30天工作饱和度
     * */
    @Override
    public List<CompositeDateVo> selectWorkAvgLinePeople(RecordSearchParamVo recordSearchParamVo) throws ParseException {
        recordSearchParamVo.setUserId(recordSearchParamVo.getDeptId());
        List<CompositeDateVo> list = selectWorkLinePeople(recordSearchParamVo);
        Integer hours = compositeMapper.selectUserWorkHours(recordSearchParamVo);
        if (null != list) {
            for (CompositeDateVo l : list) {
                l.setWorkValue(Arith.mul(Arith.div(l.getWorkValue(), hours, 4), 100));
                l.setProjectValue(Arith.mul(Arith.div(l.getProjectValue(), hours, 4), 100));
                l.setTotalValue(Arith.mul(Arith.div(l.getTotalValue(), hours, 4), 100));
            }
        }
        return list;
    }

    /*
     * 计算人员工作量曲线
     * */
    public List<LineDataVo> countLineData(RecordSearchParamVo recordSearchParamVo,List<FileProcessUser> listProcessUser) throws ParseException{
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List<LineDataVo> lineDataList = new ArrayList<LineDataVo>();
        Date searchBeginTime = sdf.parse(recordSearchParamVo.getBeginTime());
        Date searchEndTime = sdf.parse(recordSearchParamVo.getEndTime());
        String name = "";
        Long userId = null;
        if(listProcessUser.size()>0){
            name = listProcessUser.get(0).getUser().getNickName();
            userId = listProcessUser.get(0).getUserId();
        }
        // TODO: 2020/10/27 遍历数组拆分工时，将工时拆分到每一天上，并删除查询时间外的数据
        for (FileProcessUser lp : listProcessUser) {
            Date startTime = lp.getStartTime();
            Date finishTime = lp.getFinishTime();
            // 计算天数时间差
            long day = DateUtil.getDatePoorDay(finishTime, startTime) + 1;
            // 每日文件时长
            double reCount = Arith.div(Double.valueOf(String.valueOf(lp.getFileHours())), day, 2);
            for (int i = 0; i < day; i++) {
                //获取指定日期前的日期
                Date relTime = DateUtil.getDatePoorDayReDate(startTime, -i, "yyyy-MM-dd");
                //实际时间- 查询开始时间
                Long poorStart = DateUtil.getDateMinus(relTime, searchBeginTime);
                //实际时间 - 查询结束时间
                Long poorEnd = DateUtil.getDateMinus(relTime, searchEndTime);
                //在查询时间端内的数据
                if (poorStart >= 0 && poorEnd <= 0) {
                    LineDataVo lineData = new LineDataVo();
                    lineData.setTime(sdf.format(relTime));
                    lineData.setValue(reCount);
                    lineDataList.add(lineData);
                }
            }
        }
        // TODO: 2020/10/27 根据时间进行聚合数组
        Map<String, List<LineDataVo>> groupByTimeMap = lineDataList.stream().collect(Collectors.groupingBy(LineDataVo::getTime));

        long day = DateUtil.getDatePoorDay(searchEndTime, searchBeginTime);
        List<LineDataVo> ldlist = new ArrayList<>();
        // TODO: 2020/10/27 补充没有工作量的日期，并对存在的工作量加和
        Double value;

        for (int i = 0; i < day; i++) {
            String relTime = DateUtil.getDatePoorDay(searchBeginTime, -i, "yyyy-MM-dd");
            LineDataVo ldv = new LineDataVo();
            List<LineDataVo> list = groupByTimeMap.get(relTime);
            value = 0.0;
            if (list != null && list.size() != 0) {
                for (LineDataVo lv : list) {
                    value += lv.getValue();
                }
            }
            ldv.setName(name);
            ldv.setUserId(userId);
            ldv.setTime(relTime);
            ldv.setValue(Arith.div(value, 1, 2));
            ldlist.add(ldv);
        }


        return ldlist;
    }

    /*
     * 计算所和科室工作饱和度
     * */
    public List<CompositeDateVo> setValue(List<CompositeDateVo> list, List<NameValueVo> plist, RecordSearchParamVo recordSearchParamVo) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        long day = DateUtil.getDatePoorDay(sdf.parse(recordSearchParamVo.getEndTime()), sdf.parse(recordSearchParamVo.getBeginTime())) + 1;
        for (CompositeDateVo nv : list) {
            Double hours = 0.0;
            for (NameValueVo n : plist) {
                if (n.getId().equals(nv.getId())) {
                    hours = n.getHours();
                }
            }
            Double workValue = Arith.mul(Arith.div(Arith.div(nv.getWorkValue(), day, 4),hours, 4), 100);
            Double projectValue = Arith.mul(Arith.div(Arith.div(nv.getProjectValue(), day, 4),hours, 4), 100);
            Double totalValue = Arith.mul(Arith.div(Arith.div(Arith.add(nv.getWorkValue(),nv.getProjectValue()), day, 4),hours, 4), 100);
            nv.setWorkValue(workValue);
            nv.setProjectValue(projectValue);
            nv.setTotalValue(totalValue);
        }
        return list;
    }


}
